package com.zyf.concurrency.chapter14;

import com.zyf.concurrency.annotations.ThreadSafe;

import java.util.concurrent.locks.AbstractQueuedSynchronizer;

/**
 * 使用AbstractQueuedSynchronizer实现二元闭锁
 * 一个简单的闭锁
 * 引自原文：
 *      在OneShotLatch中，AQS状态用来表示闭锁状态一关闭(0)或者打开(1)。起初，闭锁是关闭的。
 *      OneShotLatch是一个使用AQS实现的二元闭锁。
 *      java.util.concurrent中的所有同步器类都没有直接扩展AQS，而是都将它们的相应功
 * 能委托给私有的AQS子类来实现。
 *
 * create by yifeng
 */
@ThreadSafe
public class OneShotLatch {
    private final Sync sync = new Sync();

//    当通过调用signal打开闭锁时，所有等待中的线程都将被释放，并且随后到达闭锁的线程也被允许执行。
    public void signal() {
        sync.releaseShared(0);
    }
    // 任何调用await的线程都将阻塞并直到闭锁被打开,
    //await方法
    //调用AQS的acquireSharedInterruptibly,然后接着调用OneShotLatch中的tryAcquireShared
    //方法。在tryAcquireShared的实现中必须返回一个值来表示该获取操作能否执行。如果之前
    // 已经打开了闭锁，那么tryAcquireShared将返回成功并允许线程通过，否则就会返回一个表
    // 示获取操作失败的值
    public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(0);
    }

    private class Sync extends AbstractQueuedSynchronizer {

        /**
         * 将会回调
         * {@link java.util.concurrent.locks.AbstractQueuedSynchronizer#acquireSharedInterruptibly}
         * @param arg
         * @return
         */
        @Override
        protected int tryAcquireShared(int arg) {
            // 如果闭锁是开的（state == 1）， 那么这个操作将成功，否则将失败
            return (getState() == 1) ? 1 : -1;
        }

        /**
         * 将会回调
         * 引自原文：在tryReleaseShared中将无条件地把闭锁的状态设置为打开，(通过返回值)表示该同步器处
         * 于完全被释放的状态。因而AQS让所有等待中的线程都尝试重新请求该同步器，并且由于
         * tryAcquireShared将返回成功，因此现在的请求操作将成功。
         * {@link java.util.concurrent.locks.AbstractQueuedSynchronizer#releaseShared(int)}
         * @param arg
         * @return
         */
        @Override
        protected boolean tryReleaseShared(int arg) {
            // 现在打开闭锁
            setState(1);
            // 现在其他的线程可以获取该闭锁
            return true;
        }
    }
}
